//
//  swift
//  MyBaby
//
//  Created by LYP on 2024/9/14.
//

import UIKit
import Foundation
import CommonCrypto
import CryptoKit

class OsnUtils: NSObject {

    static func b64Encode(_ data: Data) -> String? {
       //return data.base64EncodedString(options: .lineLength64Characters)
        return data.base64EncodedString()
    }
     
    static func b64Decode(_ string: String) -> Data? {
       return Data(base64Encoded: string, options: .ignoreUnknownCharacters)
    }
    
    static func toString(_ json: [String: Any]?) -> String? {
        guard let json = json,
              let data = try? JSONSerialization.data(withJSONObject: json, options: []) else {
            return nil
        }
        return String(data: data, encoding: .utf8)
    }
    
    static func toJson(_ data: Data?) -> [String: Any]? {
        guard let data = data,
              let json = try? JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [String: Any] else {
            return nil
        }
        return json
    }
    static func toJson(_ data: String?) -> [String: Any]? {
        guard let data = data,
              let json = try? JSONSerialization.jsonObject(with: data.data(using: .utf8) ?? Data(), options: .mutableContainers) as? [String: Any] else {
            return nil
        }
        return json
    }
    static func fromData(data:Data) -> [String:Any]? {
        do {
            return try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any]
        } catch {
            print("fromData: \(error)")
        }
        return nil
    }
    static func toData(package:[String:Any]) -> Data? {
        do {
            return try JSONSerialization.data(withJSONObject: package)
        } catch {
            print("toData: \(error)")
        }
        return nil
    }
    static func sha256( data: Data) -> Data {
        var result = [UInt8](repeating: 0, count: Int(CC_SHA256_DIGEST_LENGTH))
        data.withUnsafeBytes { (bytes: UnsafeRawBufferPointer) in
            _ = CC_SHA256(bytes.baseAddress, CC_LONG(data.count), &result)
        }
        return Data(result)
    }
    
    static func sha256ToString(data: Data) -> String {
        let result = sha256(data: data)
        return result.map { String(format: "%02hhx", $0) }.joined()
    }

    static func aesEncrypt(data: Data, key: Data) -> String? {
        let encData = MMSBarEDWrap.mmsBarEDWrap_eShort(key, data: data)
        return b64Encode(encData!)
    }
    
    static func aesEncrypt(dataStr: String, keyStr: String) -> String? {
        let hash = sha256(data: keyStr.data(using: .utf8)!)
        return aesEncrypt(data: dataStr.data(using: .utf8)!, key: hash)
    }
    
    static func aesDecrypt(data: Data, key: Data) -> Data? {
        return MMSBarEDWrap.mmsBarEDWrap_dShort(key, data: data)
    }
    static func aesDecrypt(dataStr: String, keyStr: String) -> String? {
        let hash = sha256(data: keyStr.data(using: .utf8)!)
        var decData = b64Decode(dataStr)
        decData = aesDecrypt(data: decData!, key: hash)
        return String(data: decData!, encoding: .utf8)
    }
    
    static func getAesKey() -> Data {
        var key = [UInt8](repeating: 0, count: 32)
        for i in 0..<32 {
            key[i] = UInt8(arc4random_uniform(256))
        }
        return Data(key)
    }
    
    static func getTimeStamp() -> Int64 {
        return Int64(Date().timeIntervalSince1970 * 1000)
    }

    static func createUUID() -> String {
        let uuid = UUID()
        return uuid.uuidString.lowercased()
    }

    static func wrapMessage(command: String, from: String, to: String, data: [String: Any]? = nil, key: String) -> [String: Any]? {
        var json:[String :Any] = [
            "command": command,
            "ver" : "1",
            "from": from,
            "to" : to
        ]
     
        // 如果data为nil，则初始化为一个空字典
        let contentData = data
        
        // 假设dic2Json是一个将字典转换为JSON字符串的函数
        let content = toString(contentData)
        json.updateValue(content as Any, forKey: "content")
        
        
        let timestamp = getTimeStamp()
        let calc = String("\(from)\(to)\(timestamp)\(content)")
        
        // 假设osnHash是一个将字符串转换为哈希值的函数
//            let hash = EcUtils.osnHash(calc.data(using: .utf8)!)
        let hash = EcUtils.osnHash(data: calc.data(using: .utf8)!)
        json["hash"] = hash
        
        json["timestamp"] = timestamp
        
        // 假设osnSign是一个使用私钥对数据进行签名的函数
        let sign = EcUtils.osnSign(priKey: key, data: hash.data(using: .utf8)!)
        json["sign"] = sign
        
        json["crypto"] = "none"
        
        return json
    }
    static func makeMessage(command: String, from: String, to: String, data: [String: Any]?, key: String?) -> [String: Any]? {
        var json:[String:Any] = [
            "command": command,
            "from": from,
            "to" : to
        ]
        if let data = data {
            let aesKey = getAesKey()
            if let jsonData = toString(data) {
                let encData = aesEncrypt(data: jsonData.data(using: .utf8) ?? Data(), key: aesKey)
                json["content"] = encData
            }else{
                json["content"] = ""
            }
            json["crypto"] = "ecc-aes"
            
            let encKey = EcUtils.ecEncrypt2(osnID: to, data: aesKey)
            json["ecckey"] = encKey
            
            let encKey2 = EcUtils.ecEncrypt2(osnID: from, data: aesKey)
            json["ecckeyFrom"] = encKey2
            
            if let key = key {
                let msgKey = sha256(data: key.data(using: .utf8)!)
                let aesKeyEncrypted = aesEncrypt(data: aesKey, key: msgKey)
                json["aeskey"] = aesKeyEncrypted
            }
        } else {
            json["content"] = "{}"
            json["crypto"] = "none"
        }
        
        let timestamp = getTimeStamp()
        let calc = "\(from)\(to)\(timestamp)\(json["content"] ?? "")"
        let hash = EcUtils.osnHash(data: calc.data(using: .utf8)!)
        json["hash"] = hash
        json["timestamp"] = timestamp
        
        if let key = key {
            let sign = EcUtils.osnSign(priKey: key, data: hash.data(using: .utf8)!)
            json["sign"] = sign
        }
        return json
    }
    static func takeMessage(json: [String: Any], key: String, osnID: String) -> [String: Any]? {
        var contentData: Data?
        var aesKey: Data?
        
        let crypto = json["crypto"] as? String
        if crypto == nil || crypto == "none" {
            guard let content = json["content"] as? String else { return [:] }
            return toJson(content.data(using: .utf8))
        } else if crypto == "ecc-aes" {
            if json["from"] as? String == osnID {
                aesKey = EcUtils.ecDecrypt2(priKey: key, data: json["ecckeyFrom"] as! String)
            } else if json["to"] as? String == osnID {
                aesKey = EcUtils.ecDecrypt2(priKey: key, data: json["ecckey"] as! String)
            } else if let aeskeyBase64 = json["aeskey"] as? String {
                contentData = b64Decode(aeskeyBase64)
                aesKey = aesDecrypt(data: contentData!, key: sha256(data: key.data(using: .utf8)!))
            } else {
                print("unknown key mode")
                return nil
            }
        } else if crypto == "aes" {
            guard let aeskeyBase64 = json["aeskey"] as? String else { return nil }
            contentData = b64Decode(aeskeyBase64)
            aesKey = aesDecrypt(data: contentData!, key: sha256(data: key.data(using: .utf8)!))
        } else {
            print("unsupport crypto")
            return nil
        }
        
        guard let contentBase64 = json["content"] as? String else { return nil }
        contentData = b64Decode(contentBase64)
        contentData = aesDecrypt(data: contentData!, key: aesKey!)
        return toJson(contentData)
        
    }

}
